package com.cscec5b.inspection.service;

import com.cscec5b.inspection.dto.UserSyncDtos.*;
import com.cscec5b.inspection.entity.IdempotentRequest;
import com.cscec5b.inspection.entity.User;
import com.cscec5b.inspection.repository.IdempotentRequestRepository;
import com.cscec5b.inspection.repository.UserRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.*;

@Service
public class UserSyncService {
    private final UserRepository userRepo;
    private final IdempotentRequestRepository idemRepo;
    private final ObjectMapper om = new ObjectMapper();

    public UserSyncService(UserRepository userRepo, IdempotentRequestRepository idemRepo) {
        this.userRepo = userRepo; this.idemRepo = idemRepo;
    }

    @Transactional
    public UserSyncResponse processSync(String clientId, String requestId, long timestamp, UserSyncRequest req) {
        String bodyHash = sha256Hex(toJson(req));
        Optional<IdempotentRequest> old = idemRepo.findByRequestId(requestId);
        if (old.isPresent()) {
            if (!old.get().getBodyHash().equalsIgnoreCase(bodyHash)) {
                throw new ConflictException();
            }
            try { return om.readValue(old.get().getResponseCache(), UserSyncResponse.class); }
            catch (Exception e) { throw new RuntimeException("deserialize cached response failed", e); }
        }

        List<UserDetail> details = new ArrayList<>(req.data.size());
        Instant now = Instant.ofEpochSecond(timestamp);

        for (UserItem it : req.data) {
            try {
                upsertUser(it, now);
                details.add(new UserDetail(it.user_code, true, null));
            } catch (Exception ex) {
                details.add(new UserDetail(it.user_code, false, ex.getMessage()));
            }
        }
        UserSyncResponse resp = new UserSyncResponse(details);

        IdempotentRequest ir = new IdempotentRequest();
        ir.setRequestId(requestId);
        ir.setClientId(clientId);
        ir.setBodyHash(bodyHash);
        try { ir.setResponseCache(om.writeValueAsString(resp)); }
        catch (Exception e) { throw new RuntimeException(e); }
        idemRepo.save(ir);

        return resp;
    }

    private void upsertUser(UserItem it, Instant syncTime) {
        User u = userRepo.findByUserCode(it.user_code).orElseGet(User::new);
        boolean isNew = (u.getUserCode() == null);
        if (isNew) u.setUserCode(it.user_code);

        u.setUsername(it.username.trim());
        u.setCompanyName(it.company_name == null ? null : it.company_name.trim());
        // ====== 仅一种类型：双MD5；规范化为小写16进制后落库 ======
        if (!looksLikeHex32(it.password)) {
            throw new IllegalArgumentException("password must be 32-hex MD5x2");
        }
        u.setPassword(it.password.toLowerCase(Locale.ROOT)); // 直接存入 user_password

        u.setLastSyncAt(Instant.now());
        u.setUpdatedAt(Instant.now());
        userRepo.save(u);
    }

    private boolean looksLikeHex32(String s) {
        return s != null && s.length() == 32 && s.matches("[0-9a-fA-F]{32}");
    }

    private static String sha256Hex(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            return HexFormat.of().formatHex(md.digest(s.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    private String toJson(Object o) {
        try { return om.writeValueAsString(o); } catch (Exception e) { throw new RuntimeException(e); }
    }

    public static class ConflictException extends RuntimeException {}
}
